package fr.cdesire.sudoku.applet.utils;

import java.util.List;
import java.util.Observable;
import java.util.Observer;

import fr.cdesire.sudoku.applet.bean.CaseBean;
import fr.cdesire.sudoku.applet.bean.GrilleBean;
import fr.cdesire.sudoku.applet.exception.SudokuAppletException;
import fr.cdesire.sudoku.applet.utils.Message.MessageEnum;
import fr.cdesire.sudoku.core.Sudoku;
import fr.cdesire.sudoku.core.commons.FormatGrille;
import fr.cdesire.sudoku.core.commons.Grille;
import fr.cdesire.sudoku.core.exceptions.SudokuCoreException;

public class SudokuManager extends Observable implements Observer {
	

	private static final int NB_CASES_LIGNE_REGION_DEFAUT = 3;
	private static final int NB_CASES_COLONNE_REGION_DEFAUT = 3;
	
	public static SudokuManager instance = null;

	private Grille grille;
	private GrilleBean grilleBean;
	private Message message;

	private SudokuManager(int nbCasesLigneRegion, int nbCasesColonneRegion) {
		
		this.message = new Message();
		
		try {
			this.grille = new Grille(nbCasesLigneRegion, nbCasesColonneRegion);
			this.grilleBean = new GrilleBean();
			this.grilleBean.addObserver(this);
			this.addObserver(grilleBean);
			
		} catch (SudokuCoreException e) {
			this.message.update(MessageEnum.MESSAGE_ERREUR_TECHNIQUE);
		}
	}
	
    public final synchronized static SudokuManager getInstance() {
        return getInstance(NB_CASES_LIGNE_REGION_DEFAUT, NB_CASES_COLONNE_REGION_DEFAUT);
    }
    
    public final synchronized static SudokuManager getInstance(int nbCasesLigneRegion, int nbCasesColonneRegion) {
        if (instance == null || instance.grille.getFormatGrille().getNbLignesRegion() != nbCasesLigneRegion || instance.grille.getFormatGrille().getNbColonnesRegion() != nbCasesColonneRegion) {
            instance = new SudokuManager(nbCasesLigneRegion, nbCasesColonneRegion);
        }
        return instance;
    }
    
    protected final synchronized static void removeInstance() {
    	instance = null;
    }
	
	public void update(String json) throws SudokuAppletException {
		grilleBean.update(json);
	}
	
	public void validerGrille() throws SudokuCoreException {
		Sudoku.valider(grille);
	}
	
	public void rechercheSolution() throws SudokuCoreException {
		grille = Sudoku.rechercheSolution(grille);
		setChanged();
		notifyObservers(grille);
	}

	@SuppressWarnings("unchecked")
	@Override
	public void update(Observable observable, Object object) {

		if (observable instanceof GrilleBean) {
			grille.clear();
			for (CaseBean cellule : (List<CaseBean>) object) {
				if (cellule.isInitiale()) {
					grille.getValeursRenseignees().put(grille.getFormatGrille().getPosition(cellule.getLigne(), cellule.getColonne()),
							((GrilleBean)observable).getValeurs().get(cellule.getValeur()));
				}
			}
		}
	}

	@Override
	public String toString() {
		return grilleBean.toString();
	}

	public Message getMessage() {
		return message;
	}
	
	public FormatGrille getFormatGrille() {
		return grille.getFormatGrille();
	}
}
